import * as d3 from 'd3'
export class CalendarChart {
    divId = ''
    date = []
    data = []
    chart = {}
    cellSize = 17
    format = d3.timeFormat('%Y-%m-%d')
    yearHeight = 136
    color = ['rgb(165, 0, 38)', 'rgb(215,48,39)', 'rgb(244,109,67)', 'rgb(253,174,97)', 'rgb(254,224,139)',
      'rgb(255,255,191)', 'rgb(217,239,139)', 'rgb(166,217,106)', 'rgb(102,189,99)', 'rgb(26,152,80)',
      'rgb(0,104,55)']

    constructor (divId) {
      this.divId = divId
    }

    draw () {
      this.initChart()
      this.drawCalendar()
      this.drawLabel()
      this.drawLegend()
      this.fillColor()
    }

    initChart () {
      this.chart.padding = {
        left: 10,
        right: 10,
        top: 10,
        bottom: 10
      }
      this.chart.divHeight = document.getElementById(this.divId).offsetHeight -
          this.chart.padding.top -
          this.chart.padding.bottom
      this.chart.divWidth = document.getElementById(this.divId).offsetWidth -
          this.chart.padding.left -
          this.chart.padding.right

      this.basicRadius = Math.min(this.chart.divHeight, this.chart.divWidth) / 2

      this.chart.svg = d3
        .select('#' + this.divId)
        .append('svg')
        .attr('width', this.chart.divWidth +
            this.chart.padding.left +
            this.chart.padding.right
        )
        .attr('height', this.chart.divHeight +
            this.chart.padding.top +
            this.chart.padding.bottom
        )
        .attr('class', 'svg_chart')

      this.chart.year = this.chart.svg.selectAll('.Year')
        .data(d3.range(this.date[0], this.date[1]))
        .enter()
        .append('g')
        .attr('transform', (_, i) => 'translate(0,' + this.yearHeight * i + ')')
        .attr('class', 'Year')

      this.chart.calendar = this.chart.year.append('g')
        .attr('transform', (_, i) => 'translate(' + (this.chart.divWidth - this.cellSize * 53) / 2 + ',' +
        (this.yearHeight - this.cellSize * 7 - 1) + ')')
    }

    drawCalendar () {
      let cellSize = this.cellSize
      this.chart.calendar.selectAll('.day')
        .data(d => d3.timeDays(new Date(d, 0, 1), new Date(d + 1, 0, 1)))
        .enter()
        .append('rect')
        .attr('class', 'day')
        .style('fill', 'white')
        .style('stroke', '#ccc')
        .attr('x', d => d3.timeWeek.count(d3.timeYear(d), d) * this.cellSize)
        .attr('y', d => d.getDay() * this.cellSize)
        .attr('width', cellSize)
        .attr('height', cellSize)
        .datum(this.format)
        .append('title')
        .text(String)

      this.chart.calendar.selectAll('.month')
        .data(d => d3.timeMonths(new Date(d, 0, 1), new Date(d + 1, 0, 1)))
        .enter()
        .append('path')
        .attr('class', 'path')
        .attr('d', monthPath)
        .style('fill', 'none')
        .style('stroke', 'black')
        .style('stroke-width', 1)

      function monthPath (t0) {
        const t1 = new Date(t0.getFullYear(), (t0.getMonth() + 1), 0) // next month
        const d0 = t0.getDay() // the first day
        const w0 = d3.timeWeek.count(d3.timeYear(t0), t0) // weeks from the first day of the year to the current day
        const d1 = t1.getDay()
        const w1 = d3.timeWeek.count(d3.timeYear(t1), t1)
        return 'M' + (w0 + 1) * cellSize + ',' + d0 * cellSize + 'H' + w0 * cellSize + 'V' +
           (7 * cellSize) + 'H' + (w1 * cellSize) + 'V' + (d1 + 1) * cellSize + 'H' +
           (w1 + 1) * cellSize + 'V' + 0 + 'H' + (w0 + 1) * cellSize + 'Z'
      }
    }

    fillColor () {
      const color = d3.scaleQuantize()
        .domain([-0.05, 0.05])
        .range(d3.range(11))

      const data = d3.nest()
        .key(d => d.Date)
        .rollup(d => (d[0].Close - d[0].Open) / d[0].Open)
        .map(this.data)

      this.chart.svg.selectAll('.day')
        .filter(d => {
          const key = '$' + d
          return key in data
        })
        .style('fill', d => {
          const value = data['$' + d]
          return this.color[color(value)]
        })
        .select('title')
        .text(d => {
          const value = data['$' + d]
          return d + '：' + value.toFixed(3)
        })
    }

    drawLegend () {
      let legendWidth = 15
      let legendHeight = 15
      let legends = this.chart.svg
        .selectAll('.legend')
        .data(this.color)
      let legendEnter = legends.enter()
        .append('g')
        .attr('class', 'legend')

      legendEnter.append('rect')
        .attr('x', this.chart.divWidth + 5)
        .attr('y', (d, i) => this.chart.padding.top + legendHeight * i)
        .attr('width', 0)
        .attr('height', legendHeight)
        .style('fill', (d, i) => this.color[i])

      let legendUpdate = legendEnter.merge(legends)

      legendUpdate.select('rect')
        .transition()
        .duration(750)
        .attr('width', legendWidth)
    }

    drawLabel () {
      this.chart.year
        .append('text')
        .attr('transform', 'translate(' + (this.chart.divWidth - this.cellSize * 53) / 2.5 + ',' +
        (this.yearHeight / 2) + ')')
        .attr('class', 'Yeartext')
        .text(String)
    }
}
